package com.jolink.omiis.wechat.http;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jolink.omiis.wechat.keys.IPreferences;
import com.jolink.omiis.wechat.util.FFMpegTransfer;
import com.jolink.omiis.wechat.util.WeChatConfiguration;

/**
 * @author WangYanqing
 * HTTP请求操作类
 *
 * @param <T>
 */
public class HttpHandler<T> implements IHttpHandler<T> {

	private static Logger logger = LoggerFactory.getLogger(HttpHandler.class);

	private static String VOICE_EXTENSION_NAME = ".mp3";
	private static String FILTER_MEDIA_EXTENSION_NAME = "amr";

	@SuppressWarnings("unchecked")
	@Override
	public T get(String uri, String reqParams) {
		logger.info("执行HTTP-GET请求开始，URI={},REQPARAMS={}。", uri, reqParams);
		long t1 = System.currentTimeMillis();
		CloseableHttpClient client = HttpClients.createDefault();
		uri = jointUrl(uri, reqParams);
		HttpGet httpUriRequest = new HttpGet(uri);
		int defaultTimeout = 30 * 1000;
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(defaultTimeout)
				.setConnectTimeout(defaultTimeout).build();
		httpUriRequest.setConfig(requestConfig);
		T t = null;
		try {
			t = client.execute(httpUriRequest, new ResponseHandler<T>() {
				@Override
				public T handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
					Map<String, String> resultMap = new HashMap<String, String>();
					String fileName = getFileName(response);
					Header[] headers = response.getHeaders("Content-Type");
					if (headers.length > 0) {
						Header header = headers[0];
						String contentType = header.getValue();
						if ("image/jpg".equals(contentType) && fileName == null) {
							fileName = UUID.randomUUID().toString() + ".jpg";
						}
					}

					if (StringUtils.isEmpty(fileName)) {
						HttpEntity httpEntity = response.getEntity();
						String entityStr = EntityUtils.toString(httpEntity, "utf-8");
						logger.info("接收到HTTP服务器响应报文：{}。", entityStr);
						return (T) entityStr;
					} else {
						String downloadPath = WeChatConfiguration.getIngleton()
								.getValue("OMIIS_MATERIAL_TEMP_DOWNLOAD_PATH");
						logger.info("HTTP文件下载，文件名：{}，HTTP服务器素材下载存放路径：{}。", fileName, downloadPath);
						InputStream is = null;
						File file = null;
						FileOutputStream fos = null;
						try {
							HttpEntity entity = response.getEntity();
							is = entity.getContent();
							file = new File(downloadPath, fileName);
							resultMap.put("fileName", fileName);
							resultMap.put("tempPath", file.getParent());
							logger.info("素材文件信息：{}。", resultMap);
							File parentFile = file.getParentFile();
							if (!parentFile.exists()) {
								parentFile.mkdirs();
							}
							byte[] buffer = new byte[5 * 1024 * 1024];
							int len = IOUtils.read(is, buffer);
							byte[] data = new byte[len];
							System.arraycopy(buffer, 0, data, 0, len);
							logger.info("读取素材文件：{}，大小：{}。", fileName, len);
							fos = new FileOutputStream(file);
							IOUtils.write(data, fos);
							if (fileName.endsWith(FILTER_MEDIA_EXTENSION_NAME)) {
								int lastDotIndex = fileName.indexOf(".");
								String newFileName = fileName.substring(0, lastDotIndex) + VOICE_EXTENSION_NAME;
								resultMap.putAll(FFMpegTransfer.transfer(file.getPath(),
										new File(file.getParentFile(), newFileName).getPath()));
								logger.info("媒体文件：{}为：{}格式，需要转制为{}，新文件名：{}。", fileName, FILTER_MEDIA_EXTENSION_NAME,
										VOICE_EXTENSION_NAME, newFileName);
							}
						} catch (IOException e) {
							logger.error(e.getMessage(), e);
						} finally {
							IOUtils.closeQuietly(is);
							IOUtils.closeQuietly(fos);
						}
					}

					long t2 = System.currentTimeMillis();
					logger.info("下载临时素材完成，耗时：{}毫秒。", (t2 - t1));
					return (T) resultMap;
				}
			});
		} catch (ClientProtocolException e) {
			logger.error(e.getMessage(), e);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		} finally {
			HttpClientUtils.closeQuietly(client);
		}
		long t2 = System.currentTimeMillis();
		logger.info("执行HTTP-GET完成，耗时：{}毫秒。", (t2 - t1));
		return t;
	}

	@Override
	public T post(String uri, String reqParams, String httpEntity) {
		logger.info("执行HTTP-POST请求开始，URI={},REQPARAMS={},HTTPENTITY={}。", uri, reqParams, httpEntity);
		long t1 = System.currentTimeMillis();
		uri = jointUrl(uri, reqParams);
		CloseableHttpClient client = HttpClients.createDefault();

		HttpPost httpPost = new HttpPost(uri);
		int defaultTimeout = 30 * 1000;
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(defaultTimeout)
				.setConnectTimeout(defaultTimeout).build();
		httpPost.setConfig(requestConfig);
		HttpEntity entity = new StringEntity(httpEntity, Consts.UTF_8);
		httpPost.setEntity(entity);
		T t = null;
		try {
			t = client.execute(httpPost, new ResponseHandler<T>() {
				@SuppressWarnings("unchecked")
				@Override
				public T handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
					HttpEntity httpEntity = response.getEntity();
					String entityStr = EntityUtils.toString(httpEntity, "utf-8");
					logger.info("接收到HTTP服务器响应报文：{}。", entityStr);
					return (T) entityStr;
				}
			});
		} catch (ClientProtocolException e) {
			logger.error(e.getMessage(), e);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		} finally {
			HttpClientUtils.closeQuietly(client);
		}
		long t2 = System.currentTimeMillis();
		logger.info("执行HTTP-POST完成，耗时：{}毫秒。", (t2 - t1));
		return t;
	}

	@Override
	public T get(String uri, Map<String, String> reqParams) {
		return get(uri, transferMap2ReqStr(reqParams));
	}

	@Override
	public T post(String uri, Map<String, String> reqParams, String httpEntity) {
		return post(uri, transferMap2ReqStr(reqParams), httpEntity);
	}

	private String transferMap2ReqStr(Map<String, String> reqParams) {
		if (reqParams == null || reqParams.isEmpty()) {
			return "";
		}
		StringBuffer reqBF = new StringBuffer();
		for (Iterator<Entry<String, String>> it = reqParams.entrySet().iterator(); it.hasNext();) {
			Entry<String, String> entry = it.next();
			String key = entry.getKey();
			String value = entry.getValue();
			reqBF.append(key).append("=").append(value).append("&");
			if (logger.isDebugEnabled()) {
				logger.debug("参数信息：key={}，value={}。", key, value);
			}
		}
		int ampLastIndex = reqBF.lastIndexOf(IPreferences.AMP);
		String reqStr = reqBF.substring(0, ampLastIndex);
		logger.info("请求参数（原）：{}，新：{}。", reqBF.toString(), reqStr);
		return reqStr;
	}

	private String jointUrl(String uri, String reqParams) {
		if (!StringUtils.isEmpty(reqParams) && uri.lastIndexOf("?") < 0) {
			uri += "?";
		}
		uri += reqParams == null ? "" : reqParams;
		logger.info("HTTP-POST：URI={}", uri);
		return uri;
	}

	@Override
	public T post(String uri, String reqParams, HttpEntity httpEntity) {
		logger.info("执行HTTP-POST请求开始，POST请求信息：URI={},REQPARAMS={},HTTPENTITY={}。", uri, reqParams, httpEntity);
		long t1 = System.currentTimeMillis();
		uri = jointUrl(uri, reqParams);
		CloseableHttpClient client = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost(uri);
		int defaultTimeout = 30 * 1000;
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(defaultTimeout)
				.setConnectTimeout(defaultTimeout).build();
		httpPost.setConfig(requestConfig);
		httpPost.setEntity(httpEntity);
		T t = null;
		try {
			t = client.execute(httpPost, new ResponseHandler<T>() {
				@SuppressWarnings("unchecked")
				@Override
				public T handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
					HttpEntity httpEntity = response.getEntity();
					String entityStr = EntityUtils.toString(httpEntity, "utf-8");
					logger.info("接收到HTTP服务器响应报文：{}。", entityStr);
					return (T) entityStr;
				}
			});
		} catch (ClientProtocolException e) {
			logger.error(e.getMessage(), e);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		} finally {
			HttpClientUtils.closeQuietly(client);
		}
		long t2 = System.currentTimeMillis();
		logger.info("执行HTTP-POST完成，耗时：{}毫秒。", (t2 - t1));
		return t;
	}

	@Override
	public T post2(String uri, String reqParams, HttpEntity httpEntity) {
		logger.info("执行HTTP-POST请求开始，POST请求信息：URI={},REQPARAMS={},HTTPENTITY={}。", uri, reqParams, httpEntity);
		long t1 = System.currentTimeMillis();
		uri = jointUrl(uri, reqParams);
		CloseableHttpClient client = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost(uri);
		int defaultTimeout = 30 * 1000;
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(defaultTimeout)
				.setConnectTimeout(defaultTimeout).build();
		httpPost.setConfig(requestConfig);
		httpPost.setEntity(httpEntity);
		T t = null;
		try {
			t = client.execute(httpPost, new ResponseHandler<T>() {
				@SuppressWarnings("unchecked")
				@Override
				public T handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
					HttpEntity httpEntity = response.getEntity();
					String entityStr = EntityUtils.toString(httpEntity, "utf-8");
					logger.info("接收到HTTP服务器响应报文：{}。", entityStr);
					return (T) entityStr;
				}
			});
		} catch (ClientProtocolException e) {
			logger.error(e.getMessage(), e);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		} finally {
			HttpClientUtils.closeQuietly(client);
		}
		long t2 = System.currentTimeMillis();
		logger.info("执行HTTP-POST完成，耗时：{}毫秒。", (t2 - t1));
		return t;
	}

	private String getFileName(HttpResponse response) {
		Header contentHeader = response.getFirstHeader("Content-Disposition");
		String fileName = null;
		if (contentHeader != null) {
			HeaderElement[] values = contentHeader.getElements();
			if (values.length == 1) {
				NameValuePair param = values[0].getParameterByName("filename");
				if (param != null) {
					try {
						// filename = new
						// String(param.getValue().toString().getBytes(),
						// "utf-8");
						// filename = URLDecoder.decode(param.getValue(),
						// "utf-8");
						fileName = param.getValue();
						logger.info("下载附件文件名：{}。", fileName);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		return fileName;
	}
}
